﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Automation;
using AgileObjects.AgileMapper;
using BDSync.Domains.DBConn;
using BDSync.Domains.DBSnapShot;
using DB.SchemaSync.Library.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;

using MSSQL.DBSync.UI.Common.AsyncCmds;
using MSSQL.DBSync.UI.Common.Messages;
using MSSQL.DBSync.UI.Components.ManageConn;
using MSSQL.DBSync.UI.Components.VOS;
using Serilog;

namespace MSSQL.DBSync.UI.Components.MakeSnapshot
{



    /// <summary>
    /// 数据库快照视图模型
    /// </summary>
    public class MakeSnapshotVM : ViewModelBase, IMakeSnapshotVM
    {
        private IDBSnapShotServices snapSvc;
        private IDBConnService mConnSvc;
        public MakeSnapshotVM()
        {
            initDesignData();
        }

        public MakeSnapshotVM(IDBSnapShotServices svc, IDBConnService connSvc)
        {
            snapSvc = svc;
            mConnSvc = connSvc;

            initDesignData();

            Messenger.Default.Register<String>(this, MessageTopics.APP_Conn_Update, GetAllHandler);
            GetAllHandler();
        }

        /// <summary>
        /// 初始化设计数据
        /// </summary>
        private void initDesignData()
        {
            DBObjectBriefs = new ObservableCollection<DBObjectBriefVO>();
            DBObjectBriefs.Add(new DBObjectBriefVO() { Name = "数据表", TypeName = DBObjectTypes.Tables, Count = 0, IsShow = false });
            DBObjectBriefs.Add(new DBObjectBriefVO() { Name = "存储过程/函数", TypeName = DBObjectTypes.Modules, Count = 0, IsShow = false });
            DBObjectBriefs.Add(new DBObjectBriefVO() { Name = "视图", TypeName = DBObjectTypes.Views, Count = 0, IsShow = false });
            DBObjectBriefs.Add(new DBObjectBriefVO() { Name = "外键", TypeName = DBObjectTypes.ForeignKeys, Count = 0, IsShow = false });
            
            Conns = new ObservableCollection<ConnObjVO>();
            //Conns.Add(new ConnObjVO {Host = "10.9.0.6", DB = "eComm", PWD = "Abc@123456!!", User= "sa" });
            //Conns.Add(new ConnObjVO { Host = "10.9.0.6", DB = "eCommTest", PWD = "Abc@123456!!", User = "sa" });

        }

        private void GetAllHandler(string msg = null)
        {
            var res = mConnSvc.FindAll();
            var objs = Mapper.Map(res).ToANew<List<ConnObjVO>>();
            Conns.Clear();
            objs.ForEach(x => Conns.Add(x));
        }

       
        public int mDBConnCheckState = 0;
        /// <summary>
        /// 0 未连通
        /// 1 已连通
        /// 2 连接错误
        /// </summary>
        public int DBConnCheckState {
            get
            {
                return mDBConnCheckState;
            }
            set
            {
                Set(ref mDBConnCheckState, value);
                //通知按钮命令状态变化
                ExportFile.RaiseCanExecuteChanged();
                ScanDB.RaiseCanExecuteChanged();
            }
        } 



        private string mConnstr;
        /// <summary>
        /// 数据连接字符串
        /// </summary>
        public string Connstr {
            get
            {
                return mConnstr;
            }
            set
            {
                Set(ref mConnstr, value);
                DBConnCheckState = 0;
            }
        }


        private string mHost;
        /// <summary>
        /// 主机
        /// </summary>
        public string Host
        {
            get
            {
                return mHost;
            }
            set
            {
                Set(ref mHost, value);
                DBConnCheckState = 0;
            }
        }

        private string mUser;
        /// <summary>
        /// 用户
        /// </summary>
        public string User
        {
            get
            {
                return mUser;
            }
            set
            {
                Set(ref mUser, value);
                DBConnCheckState = 0;
            }
        }

        private string mPwd;
        /// <summary>
        /// 密码
        /// </summary>
        public string Pwd
        {
            get
            {
                return mPwd;
            }
            set
            {
                Set(ref mPwd, value);
                DBConnCheckState = 0;
            }
        }

        private string mDataBase;
        /// <summary>
        /// 数据库
        /// </summary>
        public string DataBase
        {
            get
            {
                return mDataBase;
            }
            set
            {
                Set(ref mDataBase, value);
                DBConnCheckState = 0;
            }
        }


        private AsyncCommand mCheckConn;
        /// <summary>
        /// 初始化设置首页内容
        /// </summary>
        public AsyncCommand CheckConn
        {
            get
            {
                //非空判断
                if (mCheckConn != null) { return mCheckConn; }
                mCheckConn = new AsyncCommand(CheckConnHandler);
                return mCheckConn;
            }
            set { mCheckConn = value; }
        }

        private async Task CheckConnHandler() 
        {
            //var sampleMessageDialog = new SampleMessageDialog {Message = { Text = "" }};
            //await DialogHost.Show(sampleMessageDialog,"");
            var str = $"Data Source={Host};Initial Catalog={DataBase};User id={User};Password={Pwd}";

            //if (string.IsNullOrWhiteSpace(Connstr))
            //{
            //    Messenger.Default.Send("必须输入有效主机，用户名，密码", MessageTopics.APP_ShowError);
            //    return;
            //}

            Connstr = str;
            snapSvc.DbConnStr = Connstr;
            if (snapSvc.CheckConn())
            {
                DBConnCheckState = 1;
                Messenger.Default.Send("连接成功!", MessageTopics.APP_ShowMessage);
            }
            else
            {
                DBConnCheckState = 2;
                Messenger.Default.Send("连接失败!", MessageTopics.APP_ShowError);
            }
        }




        private string mFolder;
        /// <summary>
        /// 导出保存路径
        /// </summary>
        public string Folder
        {
            get
            {
                return mFolder;
            }
            set
            {
                Set(ref mFolder, value);
                //通知按钮命令状态变化
                ExportFile.RaiseCanExecuteChanged();
            }
        }

        private string mFileName;
        /// <summary>
        /// 导出保存路径
        /// </summary>
        public string FileName
        {
            get
            {
                return mFileName;
            }
            set
            {
                Set(ref mFileName, value);
               
            }
        }


        /// <summary>
        /// 路径设置回调
        /// </summary>
        /// <param name="path"></param>
        private void SetFolderPath(string path)
        {
            Folder = path;
        }

        private RelayCommand mOpenDir;
        /// <summary>
        /// 打开目录
        /// </summary>
        public RelayCommand OpenDir
        {
            get
            {
                //非空判断
                if (mOpenDir != null) { return mOpenDir; }
                mOpenDir = new RelayCommand( () => {
                        Messenger.Default.Send<Action<string>>(SetFolderPath,MessageTopics.APP_OpenDir);
                    }
                );
                return mOpenDir;
            }
            set { mOpenDir = value; }
        }

        private AsyncCommand mExportFile;
        /// <summary>
        /// 导出数据
        /// </summary>
        public AsyncCommand ExportFile
        {
            get
            {
                if (mExportFile != null) { return mExportFile; }
                mExportFile = new AsyncCommand(
                    ExportFileHandle,
                    () =>
                        {
                            return DBConnCheckState == 1 && !string.IsNullOrWhiteSpace(Folder);
                        }
                    );
                return mExportFile;
            }
            set { mExportFile = value; }
        }

        /// <summary>
        /// 导出数据
        /// </summary>
        /// <returns></returns>
        private async Task ExportFileHandle()
        {
            if (string.IsNullOrWhiteSpace(Folder))
            {
                Messenger.Default.Send<string>("必须先指定导出目录",MessageTopics.APP_ShowError);
                return;
            }

            var str = await snapSvc.ExportDbJson(Folder);
            FileName = str;
        }


        public ObservableCollection<DBObjectBriefVO> DBObjectBriefs { get; set; }


        private DBObjectBriefVO mCurDBObje;
        /// <summary>
        /// 当前数据库类型对象
        /// </summary>
        public DBObjectBriefVO CurDBObje
        {
            get { return mCurDBObje; }
            set
            {
                //Debug.WriteLine($"-------------curdbobj:{value.Name}");
                Set(ref mCurDBObje,value);
            }
        }

        private AsyncCommand mScanDb;
        /// <summary>
        /// 初始化设置首页内容
        /// </summary>
        public AsyncCommand ScanDB
        {
            get
            {
                if (mScanDb != null) { return mScanDb; }
                mScanDb = new AsyncCommand(ScanDBHandler,() =>
                {
                    return DBConnCheckState == 1;
                });
                return mScanDb;
            }
            set { mScanDb = value; }
        }


        /// <summary>
        /// 扫描数据处理程序
        /// </summary>
        /// <returns></returns>
        private async Task ScanDBHandler()
        {
            try
            {
                if (DBConnCheckState != 1)
                {
                    Messenger.Default.Send("数据连接必须验证通过", MessageTopics.APP_ShowError);
                    return;
                }

                var res = await snapSvc.GetDataBaseRes();
                if (res.db == null)
                {
                    Messenger.Default.Send($"扫描数据库失败:{res.msg}", MessageTopics.APP_ShowError);
                    return;
                }

                var db = res.db;

                //清空
                foreach (var dbObjectBriefVo in DBObjectBriefs)
                {
                    dbObjectBriefVo.Count = 0;
                    dbObjectBriefVo.Childs.Clear();
                }


                //设置表类型明细
                var tablesParent = DBObjectBriefs.FirstOrDefault(x => x.TypeName == DBObjectTypes.Tables);
                tablesParent.Count = (db.Tables?.Count()) ?? 0;

                GenTableVO(db, tablesParent);


                var modulesParent = DBObjectBriefs.FirstOrDefault(x => x.TypeName == DBObjectTypes.Modules);
                modulesParent.Count = (db.Modules?.Count()) ?? 0;

                GenSPVO(db, modulesParent);


                //创建存储函数汇总显示对象
                GenSFVO(db, modulesParent);

                //创建视图汇总显示对象
                var vwParent = DBObjectBriefs.FirstOrDefault(x => x.TypeName == DBObjectTypes.Views);
                vwParent.Count = (db.Views?.Count()) ?? 0;

                GenVWVO(db, vwParent);


                //创建外键汇总显示对象
                var fkParent = DBObjectBriefs.FirstOrDefault(x => x.TypeName == DBObjectTypes.ForeignKeys);
                fkParent.Count = (db.ForeignKeys?.Count()) ?? 0;

                GenFKVO(db, fkParent);
            }
            catch (Exception e)
            {
                Log.Logger.Error(e,"解析数据对象错误");
                Messenger.Default.Send("解析数据对象错误",MessageTopics.APP_ShowError);
            }

        }


        /// <summary>
        /// 创建存储函数显示对象
        /// </summary>
        /// <param name="db"></param>
        /// <param name="fkParent"></param>
        private static void GenFKVO(Database db, DBObjectBriefVO fkParent)
        {
            if (db.ForeignKeys == null) return;

            foreach (var fk in db.ForeignKeys)
            {
                //创建存储函数显示对象
                var fkvo = new DBChildObj();
                fkvo.TypeName = "ForeignKey";
                fkvo.Name = fk.Name;

                fkvo.Desc = $"全称:[{fk.Name}]";
                fkParent.Childs.Add(fkvo);
            }
        }

        /// <summary>
        /// 创建存储函数显示对象
        /// </summary>
        /// <param name="db"></param>
        /// <param name="vwParent"></param>
        private static void GenVWVO(Database db, DBObjectBriefVO vwParent)
        {
            if (db.Views == null) return;

            foreach (var vw in db.Views)
            {
                //创建存储函数显示对象
                var vwvo = new DBChildObj();
                vwvo.TypeName = "View";
                vwvo.Name = vw.Name;

                vwvo.Desc = $"全称:[{vw.Schema}].[{vw.Name}]";
                vwParent.Childs.Add(vwvo);
            }
        }


        /// <summary>
        /// 创建存储函数显示对象
        /// </summary>
        /// <param name="db"></param>
        /// <param name="modulesParent"></param>
        private static void GenSFVO(Database db, DBObjectBriefVO modulesParent)
        {
            if (db.Modules == null) return;

            var sfParent = new DBChildObj();
            sfParent.TypeName = "StoreFunctions";
            sfParent.Name = "储存函数列表";
            var sfcount = db.Modules.Count(x => x.Type == ModuleType.ScalarFunction || x.Type == ModuleType.TableFunction);
            sfParent.Desc = $"[{sfcount}]存储函数";
            modulesParent.Childs.Add(sfParent);

            foreach (var sp in db.Modules.Where(x => x.Type == ModuleType.ScalarFunction || x.Type == ModuleType.TableFunction))
            {
                //创建存储函数显示对象
                var spvo = new DBChildObj();
                spvo.TypeName = "Function";
                spvo.Name = sp.Name;
                spvo.Desc = $"[{sp.Parameters.Count()}]个参数";

                foreach (var arg in sp.Parameters)
                {
                    var argvo = new DBChildObj();
                    argvo.TypeName = "Arg";
                    argvo.Name = arg.Name;
                    argvo.Desc = $"[{arg.DataType}] {(arg.IsOutput?"[OUTPUT]":"")}";
                    spvo.Childs.Add(argvo);
                }

                sfParent.Childs.Add(spvo);
            }
        }


        /// <summary>
        /// 创建表显示对象
        /// </summary>
        /// <param name="db"></param>
        /// <param name="tablesParent"></param>
        private static void GenTableVO(Database db, DBObjectBriefVO tablesParent)
        {
            if (db.Tables == null) return;

            foreach (var tb in db.Tables)
            {
                //创建表显示对象
                var tbvo = new DBChildObj();
                tbvo.TypeName = "Table";
                tbvo.Name = tb.Name;
                tbvo.Desc = $"全称:[{tb.Schema}].[{tb.Name}]";
                tablesParent.Childs.Add(tbvo);

                //创建列集合显示
                var colsParent = new DBChildObj();
                colsParent.TypeName = "TableColumns";
                colsParent.Name = "字段列表";
                colsParent.Desc = $"[{tb.Columns.Count()}]个字段";
                tbvo.Childs.Add(colsParent);

                foreach (var col in tb.Columns)
                {
                    //创建列显示
                    var colvo = new DBChildObj();
                    colvo.Name = col.Name;
                    colvo.TypeName = "Column";
                    colvo.Desc = $"[{col.DataType}] default [{col.Default}] {(col.IsNullable ? "NULL" : "NOT NULL")}";
                    colsParent.Childs.Add(colvo);
                }

                //创建索引集合显示
                var indexParent = new DBChildObj();
                indexParent.TypeName = "TableIndexs";
                indexParent.Name = "索引列表";
                indexParent.Desc = $"[{tb.Indexes.Count()}]个索引";
                tbvo.Childs.Add(indexParent);

                foreach (var idx in tb.Indexes)
                {
                    //创建索引显示
                    var idxvo = new DBChildObj();
                    idxvo.Name = idx.Name;
                    idxvo.TypeName = "Index";
                    idxvo.Desc = $"[{idx.Type}] {(idx.IsClustered ? "Clustered" : "NO Clustered")}";
                    indexParent.Childs.Add(idxvo);
                }

                //创建触发器集合显示
                var triggerParent = new DBChildObj();
                triggerParent.TypeName = "TableTriggers";
                triggerParent.Name = "触发器列表";
                triggerParent.Desc = $"[{tb.Triggers.Count()}]个触发器";
                tbvo.Childs.Add(triggerParent);

                foreach (var tr in tb.Triggers)
                {
                    //创建触发器显示
                    var trvo = new DBChildObj();
                    trvo.Name = tr.Name;
                    trvo.TypeName = "Trigger";
                    trvo.Desc = $"[{tr.Events}] {(tr.Is_Instead_Of ? "Instead Of" : "")}";
                    triggerParent.Childs.Add(trvo);
                }
            }
        }


        /// <summary>
        /// 创建存储过程显示对象
        /// </summary>
        /// <param name="db"></param>
        /// <param name="modulesParent"></param>
        private static void GenSPVO(Database db, DBObjectBriefVO modulesParent)
        {
            if(db.Modules == null) return;

            //创建存储过程汇总显示对象
            var spParent = new DBChildObj();
            spParent.TypeName = "StoreProcedures";
            spParent.Name = "储存过程列表";
            var spcount = db.Modules.Count(x => x.Type == ModuleType.Procedure);
            spParent.Desc = $"[{spcount}]个存储过程";
            modulesParent.Childs.Add(spParent);

            foreach (var sp in db.Modules.Where(x => x.Type == ModuleType.Procedure))
            {
                //创建触发器显示
                var spvo = new DBChildObj();
                spvo.TypeName = "Procedure";
                spvo.Name = sp.Name;

                spvo.Desc = $"[{sp.Parameters.Count()}]个参数";

                foreach (var arg in sp.Parameters)
                {
                    var argvo = new DBChildObj();
                    argvo.TypeName = "Arg";
                    argvo.Name = arg.Name;
                    argvo.Desc = $"[{arg.DataType}] {(arg.IsOutput ? "[OUTPUT]" : "")}";
                    spvo.Childs.Add(argvo);
                }

                spParent.Childs.Add(spvo);
            }

        }


        public ObservableCollection<ConnObjVO> Conns { get; set; }

        private ConnObjVO mCurConn;
        /// <summary>
        /// 数据库
        /// </summary>
        public ConnObjVO CurConn
        {
            get
            {
                return mCurConn;
            }
            set
            {
                Set(ref mCurConn, value);
                if (mCurConn != null)
                {
                    DataBase = mCurConn.DB;
                    User = mCurConn.User;
                    Pwd = mCurConn.PWD;
                    Host = mCurConn.Host;
                }
            }
        }


        private RelayCommand mGotoConnEdit;
        /// <summary>
        /// 打开目录
        /// </summary>
        public RelayCommand GotoConnEdit
        {
            get
            {
                //非空判断
                if (mGotoConnEdit != null) { return mGotoConnEdit; }
                mGotoConnEdit = new RelayCommand(() =>
                {
                    Messenger.Default.Send(typeof(IManageConnView), MessageTopics.APP_GotoPage);
                });
                return mGotoConnEdit;
            }
            set { mGotoConnEdit = value; }
        }


    }

}